#pragma once
#include <iostream>
#include <string>
#include <memory>

#include <cerrno>
#include <cstdio>
#include <cstring>
#include <cassert>

#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

#include "ThreadPool/log.hpp"
#include "ThreadPool/threadPool.hpp"
#include "ThreadPool/Task.hpp"

static void service(int sock, const std::string &clientip, const uint16_t &clientport)
{
    // echo
    char buffer[1024];
    while (true)
    {
        // read和write可以直接使用
        // 读取数据
        ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
        if (s > 0)
        {
            buffer[s] = 0; // 将发过来的消息当做字符串
            std::cout << clientip << " : " << clientport << "# " << buffer << std::endl;
        }
        else if (s == 0)
        {
            // 代表对端关闭连接
            logMessage(NORMAL, "%s:%d shutdown , me too", clientip.c_str(), clientport);
            break; // 跳出循环结束通信
        }
        else
        {
            logMessage(ERROR, "read sock error, %d:%s", errno, strerror(errno));
            break;
        }

        // 写回数据
        write(sock, buffer, strlen(buffer));
    }
    close(sock);
}

// class ThreadData
// {
// public:
//     int sock;
//     uint16_t port;
//     std::string ip;
// };

class TcpServer
{
public:
    const static int g_backlog = 20;
    // static void *threadRoutine(void *args)
    // {
    //     pthread_detach(pthread_self()); // 线程分离
    //     ThreadData *td = (ThreadData *)args;
    //     service(td->sock, td->ip, td->port);

    //     delete td;

    //     return nullptr;
    // }

public:
    TcpServer(uint16_t port, std::string ip = "")
        : _port(port), _ip(ip), listensock(-1), _threadpool_ptr(ThreadPool<Task>::getThreadPool())
    {
    }

    void initServer()
    {
        // 创建socket
        listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock < 0)
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "sock: %d", listensock);

        // bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        if (bind(listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
            exit(3);
        }
        logMessage(NORMAL, "bind success ...");

        // tcp面向连接的，通信前要先建立连接，设置为监听状态，listen
        if (listen(listensock, g_backlog) < 0)
        {
            logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "listen success ...");

        logMessage(NORMAL, "init server success");
    }

    void start()
    {
        // signal(SIGCHLD, SIG_IGN); // 子进程退出向父进程发送SIGCHLD，直接忽略这个信号，子进程退出就自动释放僵尸状态
        
        _threadpool_ptr->run();

        while (true)
        {
            // 获取连接accept
            struct sockaddr_in src; // 客户端addr
            socklen_t len = sizeof(src);
            int servicesock = accept(listensock, (struct sockaddr *)&src, &len);
            if (servicesock < 0)
            {
                logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                // 接收失败也不影响，继续接收
                continue;
            }

            // 获取连接成功
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "link success, servicesock: %d | %s : %d|\n", servicesock, client_ip.c_str(), client_port);

            // v3 -- 线程池
            Task t(servicesock, client_ip, client_port, service);
            _threadpool_ptr->pushTask(t);

            // v3 -- 多线程
            // ThreadData *td = new ThreadData();
            // td->sock = servicesock;
            // td->ip = client_ip;
            // td->port = client_port;
            // pthread_t tid;
            // // 多线程就不用关闭listensock文件描述符了，线程共享这些文件描述符
            // pthread_create(&tid, nullptr, threadRoutine, (void *)td);
            // close(servicesock);

            // v1 -- 单进程循环版
            // service(servicesock, client_ip, client_port);

            // v2 -- 多进程版
            // pid_t id = fork();
            // assert(id != -1);
            // if (id == 0)
            // {
            //     // 子进程
            //     close(listensock);
            //     if (fork() > 0) exit(0); // 子进程fork创建孙子进程，子进程exit退出了
            //     // 孙子进程就变成了孤儿进程，孤儿进程会被系统领养，执行完后由操作系统释放
            //     service(servicesock, client_ip, client_port);
            //     exit(0);
            // }
            // // 父进程
            // close(servicesock);
            // waitpid(id, nullptr, 0); //阻塞式等待子进程退出

            // pid_t id = fork();
            // assert(id != -1);
            // if (id == 0)
            // {
            //     // 子进程
            //     // 子进程也会继承父进程的文件与文件fd
            //     // 子进程提供服务，他不用管监听的事，所以要关闭
            //     close(listensock);
            //     service(servicesock, client_ip, client_port);
            //     exit(0);
            // }
            // // 父进程
            // // 父进程只需要接收sock，所以要关闭服务sock
            // close(servicesock);
        }
    }

    ~TcpServer()
    {
        if (listensock > 0)
            close(listensock);
    }

private:
    uint16_t _port;
    std::string _ip;
    int listensock;
    std::unique_ptr<ThreadPool<Task>> _threadpool_ptr;
};